package project3;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Shape;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Rectangle2D;
import java.util.HashMap;
import java.util.Map;
import javax.swing.JPanel;

/**Draws a Grid used for visualizing query results.
 *
 * Original concept from:
 * http://www.java-forums.org/new-java/8091-how-can-i-draw-board-2d-array.html
 */
 public class MakingAGrid extends JPanel
 {
    final int PAD = 0;
    int ROWS;
    int COLS;
    Map<Document,double[]> documents;

    /** Updates the documents used in the visualization. Value of this map should be
     * a length 3 array of doubles, where arr[1] is the x value, arr[2] is the y value
     * when visualized.
     */
    public void setDocuments(Map<Document, double[]> m) {
		this.documents = m;
	}

	public MakingAGrid(Map<Document,double[]> _m) {
        ROWS = 75;
        COLS = 95;
        documents = _m;
    }

    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        Graphics2D g2 = (Graphics2D)g;

        double w = getWidth();
        double h = getHeight();

        double xInc = (double)(w - 2*PAD)/COLS;
        double yInc = (double)(h - 2*PAD)/ROWS;
 
        double maxX;
    	double maxY;
    	
         g2.setPaint(Color.blue);
         
        for(int i = 0; i <= COLS; i++) {
            double x = i*(w/(double)COLS);

            for(int j = 0; j <= ROWS; j++) {
              double y = j*(h/(double)ROWS);
              Rectangle2D r = new Rectangle2D.Double(x,y,(w/(double)COLS),(h/(double)ROWS));
              g2.draw(r);
              double goodness=Math.pow(Goodness.getGoodness(x+1, y+1),.45)*(double)(j);
              g2.setPaint(goodnessTransform(goodness));
              g2.fill(r);
            }
        }
        
        Map<String,double[]> tags =  new HashMap();
    	
    	String s1 = "Low Goodness, Low Info";
    	double[] v1 = new double[3];
    	v1[1] = 0;
    	v1[2] = 0;
    	tags.put(s1, v1);
    	
    	String s2 = "High Goodness, Low Info";
    	double[] v2 = new double[3];
    	v2[1] = 0;
    	v2[2] = 100;
    	tags.put(s2, v2);
    	
    	String s3 = "High Goodness, High Info";
    	double[] v3 = new double[3];
    	v3[1] = 100;
    	v3[2] = 100;
    	tags.put(s3, v3);
    	
    	String s4 = "Low Goodness, High Info";
    	double[] v4 = new double[3];
    	v4[1] = 100;
    	v4[2] = 0;
    	tags.put(s4, v4);
    	
    	String s5 = "Mediocre Return Sector";
    	double[] v5 = new double[3];
    	v5[1] = 33;
    	v5[2] = 33;
    	tags.put(s5, v5);
    	
    	String s6 = "'Ideal' Return Sector";
    	double[] v6 = new double[3];
    	v6[1] = 80;
    	v6[2] = 80;
    	tags.put(s6, v6);
    	
        maxX = findMaxX(tags);
    	maxY = findMaxY(tags);
    	
    	for(String d : tags.keySet()){
    		// (x,y) would represent the document, (textx,texty) represents the title of the document
    		double SIZE = 10;
    		double CIRCLEBUFFER = 10;
    		double TEXTXLENGTHBUFFER = 5;
    		double TEXTXBUFFER = 5;
    		double TEXTYLENGTHBUFFER = 25;
    		double TEXTYBUFFER = 12;
    		double x = ((tags.get(d)[1]/maxX)*w)-CIRCLEBUFFER;
    		double y = ((tags.get(d)[2]/maxY)*h)-CIRCLEBUFFER;
    		int textX = (int)(((tags.get(d)[1]/maxX)*w)-TEXTXBUFFER);
    		int textY = (int)(((tags.get(d)[2]/maxY)*h)-TEXTYBUFFER);
    		//Handle the special case where the buffer makes x <= 0
    		if(x<=0){
    			x = 0;
    			textX = 0;
    		}
    		//Handle the special case where the buffer makes y <= 0
    		if(y<=0){
    			y = 0;
    			textY = 0;
    		}
    		//create the circle representing the document
    		Shape circle = new Rectangle2D.Double(x,y,SIZE,SIZE);
    		g2.draw(circle);
    		g2.setPaint(Color.BLUE);
    		g2.fill(circle);
    		//Make sure the text wont go off screen in the x direction
    		if(x+d.length()*TEXTXLENGTHBUFFER > w){
    			textX = (int) (textX - d.length()*TEXTXLENGTHBUFFER);
    		}
    		//Make sure the text wont go off screen in the y direction
    		if(y<(SIZE*2)){
    			textY = (int) (textY + TEXTYLENGTHBUFFER);
    		}
    		g2.drawString(d, textX, textY);
    	}/**/
        maxX = 0;
        maxY = 0;
        //If a Query was performed (ie. the Map is no longer null), Plot the relation of documents
        if(documents!=null){
        	maxX = findMaxX(documents);
        	maxY = findMaxY(documents);
        	for(Document d : documents.keySet()){
        		// (x,y) would represent the document, (textx,texty) represents the title of the document
        		double SIZE = 10;
        		double CIRCLEBUFFER = 10;
        		double TEXTXLENGTHBUFFER = 5;
        		double TEXTXBUFFER = 5;
        		double TEXTYLENGTHBUFFER = 25;
        		double TEXTYBUFFER = 12;
        		double x = ((documents.get(d)[1]/maxX)*w)-CIRCLEBUFFER;
        		double y = ((documents.get(d)[2]/maxY)*h)-CIRCLEBUFFER;
        		int textX = (int)(((documents.get(d)[1]/maxX)*w)-TEXTXBUFFER);
        		int textY = (int)(((documents.get(d)[2]/maxY)*h)-TEXTYBUFFER);
        		//Handle the special case where the buffer makes x <= 0
        		if(x<=0){
        			x = 0;
        			textX = 0;
        		}
        		//Handle the special case where the buffer makes y <= 0
        		if(y<=0){
        			y = 0;
        			textY = 0;
        		}
        		//create the circle representing the document
        		Shape circle = new Ellipse2D.Double(x,y,SIZE,SIZE);
        		g2.draw(circle);
        		g2.setPaint(Color.CYAN);
        		g2.fill(circle);
        		//Make sure the text wont go off screen in the x direction
        		if(x+d.getTitle().length()*TEXTXLENGTHBUFFER > w){
        			textX = (int) (textX - d.getTitle().length()*TEXTXLENGTHBUFFER);
        		}
        		//Make sure the text wont go off screen in the y direction
        		if(y<(SIZE*2)){
        			textY = (int) (textY + TEXTYLENGTHBUFFER);
        		}
        		g2.drawString(d.getTitle(), textX, textY);
        	}
        }

     }

    /**Converts a goodness value into a nice and friendly Color. Based on a gradient function.*/
     Color goodnessTransform(double d){

         d = Math.log1p(d) / Math.log1p(COLS*1.6);
         float r=0,g=0,b=0;
        if(d < .333f){
            r=(float)(d/0.333);
        }
        else if(d < .666f){
            r=1;
            g=(float)((d-.333)/.334);
        }
        else{
            r=1;
            g=1;
            b=(float)((d-.666)/(.334));
        }
        r=Math.min(r, 1);
        g=Math.min(g, 1);
        b=Math.min(b, 1);
        return new Color(r,g,b);
    }

    /**Search every document in the map and find the greatest X (d[1]) Value*/
     <Q> double findMaxX(Map<Q,double[]> m2){
         double max = 0;
         for(Q d : m2.keySet()){
             if(m2.get(d)[1] > max){
                 max = m2.get(d)[1];
             }
         }
         return max;
     }

    /**Search every document in the map and find the greatest Y (d[2]) Value*/
    <R> double findMaxY(Map<R, double[]> m2){
         double max = 0;
         for(R d : m2.keySet()){
             if(m2.get(d)[2] > max){
                 max = m2.get(d)[2];
             }
         }
         return max;
     }
}
